#include "pluginsmanager.h"

#include <QString>
#include <QList>
#include <QLibrary>
#include <QDir>
#include <QApplication>
#include <QFileInfo>
#include <QDebug>
#include "../database_plugins/idatabase.h"

typedef PLUGININFO (*MyPrototype)();

//TODO
//create global plugin interface (now only DB plugins are handle)
class PluginsManager::PluginEntry{
public:
	PluginEntry() : m_pLoader(NULL), m_loaded(false){}
	QPluginLoader *m_pLoader;
	PLUGININFO m_info;
	bool m_loaded;
};

class PluginsManager::PluginsManagerPrivate{
public:
	PluginsManagerPrivate();
	~PluginsManagerPrivate();

	QDir m_pluginsDir;


	QList<PluginEntry> m_list;

	bool m_loaded;

};

PluginsManager::PluginsManagerPrivate::PluginsManagerPrivate(){
	m_pluginsDir.setPath( QApplication::applicationDirPath() + "/plugins" );

	m_loaded = false;
}

PluginsManager::PluginsManagerPrivate::~PluginsManagerPrivate(){
	for( int i = 0; i < m_list.count(); i++ ){
		if( m_list.at(i).m_pLoader->unload() )
			delete m_list.at(i).m_pLoader;
	}
}

//end of d-class part
//------------------------------------------------------------------------------
PluginsManager::PluginsManager(QObject *parent) :
	QObject(parent),
	d(new PluginsManagerPrivate())
{

	QLibrary lib;
	foreach (QString fileName, d->m_pluginsDir.entryList(QDir::Files)) {
		if( !QLibrary::isLibrary(fileName) )
			continue;

		QPluginLoader *loader =
				new QPluginLoader(d->m_pluginsDir.absoluteFilePath(fileName));

		lib.setFileName( loader->fileName() );
		lib.load();
		MyPrototype fun =
				reinterpret_cast<MyPrototype>( lib.resolve("getPluginInfo") );

		PluginEntry entry;
		entry.m_pLoader = loader;

		if( fun )
			entry.m_info = fun();

		lib.unload();

		d->m_list.push_back( entry );
	}

}

PluginsManager::~PluginsManager(){
	delete d;
}


QObject* PluginsManager::loadPlugin(const QString &fileName){
	QFileInfo fi;
	QList<PluginEntry>::iterator it;
	QObject* toReturn = NULL;

	for(it = d->m_list.begin(); it != d->m_list.end(); it++ ){
		fi.setFile( static_cast<PluginEntry>(*it).m_pLoader->fileName());
		if( fileName.toLower() == fi.fileName().toLower() ){
			if( static_cast<PluginEntry>(*it).m_pLoader->load() ){
				toReturn = static_cast<PluginEntry>(*it).m_pLoader->instance();
				static_cast<PluginEntry&>(*it).m_loaded = true;
				d->m_loaded = true;
				qDebug() << "Plugin loaded:"
						 << static_cast<PluginEntry>(*it).m_info.shortName;
			}else{
				qWarning( )<< static_cast<PluginEntry>
												(*it).m_pLoader->errorString();
			}
		}else
			static_cast<PluginEntry>(*it).m_pLoader->unload();
	}
	return toReturn;
}

bool PluginsManager::unloadPlugin(const QString &fileName){
	QFileInfo fi;
	QList<PluginEntry>::const_iterator it;

	for(it = d->m_list.constBegin(); it != d->m_list.constEnd(); it++ ){
		fi.setFile( static_cast<PluginEntry>(*it).m_pLoader->fileName());
		if( fileName.toLower() == fi.fileName().toLower() ){
			if( static_cast<PluginEntry>(*it).m_pLoader->unload() ){
				static_cast<PluginEntry>(*it).m_loaded = false;
				d->m_loaded = false;
				qDebug() << "Plugin unloaded:"
						 << static_cast<PluginEntry>(*it).m_info.shortName;
				return true;
			}
		}
	}
	return false;
}

QList<PluginsManager::PluginsListEntry> PluginsManager::pluginsList() const {
	QList<PluginsManager::PluginsListEntry> tmp;

	QFileInfo fi;
	QList<PluginEntry>::const_iterator it;
	for(it = d->m_list.constBegin(); it != d->m_list.constEnd(); it++ ){
		fi.setFile( static_cast<PluginEntry>(*it).m_pLoader->fileName());

		PluginsListEntry entry;

		entry.fileName = fi.fileName().toLower();
		//entry.info = static_cast<PluginEntry>(*it).m_info;
		entry.title = static_cast<PluginEntry>(*it).m_info.shortName;
		entry.isLoaded = static_cast<PluginEntry>(*it).m_loaded;

		tmp.push_back( entry );
	}

	return tmp;
}
